package com.konsung.ksdc.service;

import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Binder;
import android.os.IBinder;
import android.support.annotation.Nullable;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.ibm.mqtt.MqttException;
import com.ibm.mqtt.MqttPersistenceException;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.dao.RuntimeExceptionDao;
import com.j256.ormlite.stmt.DeleteBuilder;
import com.j256.ormlite.stmt.QueryBuilder;
import com.konsung.ksdc.bean.MqttMsgBean;
import com.konsung.ksdc.bean.MqttMsgNotice;
import com.konsung.ksdc.bean.netbean.GroupNetBean;
import com.konsung.ksdc.bean.netbean.RegisterUserNetBean;
import com.konsung.ksdc.common.database.DatabaseHelper;
import com.konsung.ksdc.common.mqtt.KsdcMqttClient;
import com.konsung.ksdc.common.network.RequestCallback;
import com.konsung.ksdc.common.network.RequestUtils;
import com.konsung.ksdc.common.network.ResponseBean;
import com.konsung.ksdc.common.utils.BroadCastActions;
import com.konsung.ksdc.common.utils.Constants;
import com.konsung.ksdc.common.utils.JsonUtils;
import com.konsung.ksdc.config.NetConfig;

import org.json.JSONObject;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import okhttp3.Call;
import okhttp3.Response;

/**
 * Mqtt服务，此服务主要负责MQTT客户端的数据、链接初始化，心跳等管理。
 * Created by andy on 2017/4/17.
 */
public class MqttService extends Service {
    public static final String TAG = "MqttService";

    public static KsdcMqttClient mqttClient;
    private MqttBinder binder = new MqttBinder();
    private boolean isLoadingData; // 是否正在初始化联系人等基础数据
    private boolean isContactsLoaded; // 联系人是否加载，只要联系人被加载过一次，则不再加载
    private boolean isGroupsLoaded; // 群组是否加载，只要群组信息被加载过一次，则不再加载
    private boolean stopThread; // 是否停止心跳
    public static final long HEART_LINE = 5000; // 心跳时长5S

    private MyThread heartThread;

    @Override
    public void onCreate() {
    }

    /**
     * 启动心跳
     */
    private void startKeepAlive() {
        if (heartThread != null && heartThread.isAlive()) {
            return;
        }
        heartThread = new MyThread();
        heartThread.start();
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        startKeepAlive();
        registerReceiver();
        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        stopThread = true;
        disconnectMqttClient();
        isLoadingData = false;
        isContactsLoaded = false;
        isGroupsLoaded = false;
        unregisterReceiver(receiver);
    }

    /**
     * 初始化MQTT客户端
     * @throws MqttException 异常
     */
    public void initKsdcMqttClient() throws MqttException {
        if (mqttClient != null && mqttClient.isConnected()) {
            return;
        }
        // 客户端ID
        String clientId = NetConfig.currentUser.getUserName();

        // 订阅的主题
        String[] subscribeTopics = getSubscribeTopics();

        // 初始化MQTT服务器连接
        mqttClient = new KsdcMqttClient(clientId, subscribeTopics);
    }

    /**
     * 注册消息广播
     */
    private void registerReceiver() {
        IntentFilter intent = new IntentFilter();
        intent.addAction(BroadCastActions.ACTION_REQUEST_GROUP_RECEIVED);
        intent.addAction(BroadCastActions.ACTION_DELETE_GROUP_RECEIVED);
        registerReceiver(receiver, intent);
    }

    /**
     * 广播接收者
     */
    private BroadcastReceiver receiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (BroadCastActions.ACTION_REQUEST_GROUP_RECEIVED.equals(intent.getAction())) {
                //更新头像，群名，添加新成员
                String msgString = intent.getStringExtra(BroadCastActions.EXTRA_MESSAGE);
                MqttMsgBean bean = JsonUtils.toEntity(msgString, MqttMsgBean.class);
                if (bean != null) {
                    if (mqttClient != null) {
                        try {
                            mqttClient.subscribe(new String[]{bean.getMsgContent()}, new int[]{2});
                        } catch (MqttException e) {
                            e.printStackTrace();
                        }
                        storeDb(bean.getMsgContent());
                    }
                }
            } else if (BroadCastActions.ACTION_DELETE_GROUP_RECEIVED.equals(intent.getAction())) {
                //移除群成员
                String msgString = intent.getStringExtra(BroadCastActions.EXTRA_MESSAGE);
                MqttMsgBean bean = JsonUtils.toEntity(msgString, MqttMsgBean.class);
                if (bean != null) {
                    if (mqttClient != null) {
                        //获取最新的群数据，查询本地是否有该群，有则更新，无则删除
                        String groupId = bean.getMsgContent().split(",")[0];
                        deleteDb(groupId, bean.getMsgContent());
                    }
                }
            }
        }
    };

    /**
     * 移除群成员消息的广播
     * @param strings groupId+userId
     * @param groupId 群组id
     */
    private void deleteDb(final String groupId, final String strings) {
        RequestUtils.findCommunityById(groupId, new RequestCallback() {
            @Override
            public void onError(Call call, Exception e) {
            }

            @Override
            public void onResponse(ResponseBean responseBean) {
                if (responseBean.getResultCode().equals(Constants.REQUEST_OK)) {
                    //得到服务器最新的群组数据
                    GroupNetBean group = responseBean.getEntity(GroupNetBean.class);
                    List<RegisterUserNetBean> list = group.getUsers();
                    //得到本地群组对应的用户数据
                    if (strings.contains(NetConfig.currentUser.getUserId())) {
                        try {
                            mqttClient.unsubscribe(new String[]{groupId});
                        } catch (MqttException e) {
                            e.printStackTrace();
                        }
                        removeLocal(groupId);
                    } else {
                        //没有被移除，更新本地数据库
                        updateDb(group, groupId);
                    }
                }
            }
        });
    }

    /**
     * 清除数据
     * @param groupId 群组id
     */
    private void removeLocal(String groupId) {
        //移除自己的时候，发送广播在消息列表动态清除
        Intent intent = new Intent();
        intent.setAction(BroadCastActions.ACTION_DELETE_GROUP_ME);
        sendBroadcast(intent);

        removeLocalDb(groupId);
        removeMsg(groupId);
        removeNotice(groupId);
    }

    /**
     * 删除提醒
     * @param groupId 群组id
     */
    private void removeNotice(String groupId) {
        RuntimeExceptionDao dao = DatabaseHelper.getHelper(this)
                .getRuntimeExceptionDao(MqttMsgNotice.class);
        DeleteBuilder db = dao.deleteBuilder();
        try {
            db.where().eq("topicName", groupId).and().eq("ownerUserId", NetConfig.currentUser.
                    getUserId());
            dao.delete(db.prepare());
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    /**
     * 删除本地聊天记录
     * @param groupId 群组id
     */
    private void removeMsg(String groupId) {
        RuntimeExceptionDao dao = DatabaseHelper.getHelper(this)
                .getRuntimeExceptionDao(MqttMsgBean.class);
        DeleteBuilder db = dao.deleteBuilder();
        try {
            db.where().eq("topicName", groupId).and().eq("ownerUserId", NetConfig.currentUser.
                    getUserId());
            dao.delete(db.prepare());
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    /**
     * 更新到本地
     * @param group 最新的数据
     * @param groupId 群组id
     */
    private void updateDb(GroupNetBean group, String groupId) {
        try {
            Dao daoUpdate = DatabaseHelper.getHelper(MqttService.this).
                    getDao(GroupNetBean.class);
            QueryBuilder qbUpdate = daoUpdate.queryBuilder();
            qbUpdate.where().eq("groupId", groupId).and().eq("ownerId",
                    NetConfig.currentUser.getUserId());
            List<GroupNetBean> groups = daoUpdate.query(qbUpdate.prepare());
            if (groups != null && groups.size() > 0) {
                GroupNetBean bean = groups.get(0);
                bean.setGroupId(groupId);
                bean.setOwnerId(NetConfig.currentUser.getUserId()); //用户更新
                bean.setGroupOwnerId(group.getGroupOwnerId());
                bean.setGroupName(group.getGroupName());
                bean.setGroupPic(group.getGroupPic());
                bean.setUsers(group.getUsers()); //设置群组成员集合
                daoUpdate.update(group);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    /**
     * 删除本地数据
     * @param groupId 群组id
     */
    private void removeLocalDb(String groupId) {
        try {
            Dao dao = DatabaseHelper.getHelper(this).getDao(GroupNetBean.class);
            DeleteBuilder db = dao.deleteBuilder();
            db.where().eq("groupId", groupId).and().eq("ownerId", NetConfig.
                    currentUser.getUserId());
            dao.delete(db.prepare());
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    /**
     * 存储到数据库里
     * @param groupId 群组id
     */
    private void storeDb(final String groupId) {
        RequestUtils.findCommunityById(groupId, new RequestCallback() {
            @Override
            public void onError(Call call, Exception e) {
            }

            @Override
            public void onResponse(ResponseBean responseBean) {
                if (responseBean.getResultCode().equals(Constants.REQUEST_OK)) {
                    try {
                        GroupNetBean group = responseBean.getEntity(GroupNetBean.class);
                        Dao dao = DatabaseHelper.getHelper(MqttService.this).
                                getDao(GroupNetBean.class);
                        QueryBuilder qb = dao.queryBuilder();
                        qb.where().eq("groupId", groupId).and().eq("ownerId",
                                NetConfig.currentUser.getUserId());
                        List<GroupNetBean> groups = dao.query(qb.prepare());
                        if (groups != null && groups.size() > 0) {
                            //说明群有变更，更新到本地
                            GroupNetBean bean = groups.get(0);
                            bean.setGroupId(groupId);
                            bean.setOwnerId(NetConfig.currentUser.getUserId()); //用户更新
                            bean.setGroupOwnerId(group.getGroupOwnerId());
                            bean.setGroupName(group.getGroupName());
                            bean.setGroupPic(group.getGroupPic());
                            bean.setUsers(group.getUsers()); //设置群组成员集合
                            dao.update(bean);
                        } else {
                            Dao storeDao = DatabaseHelper.getHelper(MqttService.this)
                                    .getDao(GroupNetBean.class);
                            group.setOwnerId(NetConfig.currentUser.getUserId());
                            storeDao.createOrUpdate(group);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        });
    }

    /**
     * 取当前用户订阅的消息
     * @return 信息
     */
    private String[] getSubscribeTopics() {
        List<String> topics = new ArrayList<String>();
        //进入app订阅我的以及康尚的推送主题
        topics.add(NetConfig.currentUser.getUserName());
        topics.add(Constants.TOPIC_KSBK);

        List<GroupNetBean> groups = DatabaseHelper.getHelper(this)
                .getRuntimeExceptionDao(GroupNetBean.class)
                .queryForEq("ownerId", NetConfig.currentUser.getUserId());
        for (GroupNetBean group : groups) {
            topics.add(group.getGroupId());
        }

        return topics.toArray(new String[topics.size()]);
    }

    /**
     * 客户端是否连接
     * @return boolen值
     */
    public static boolean isMqttConnected() {
        return mqttClient != null && mqttClient.isConnected();
    }

    /**
     * 断开Mqtt链接
     */
    public void disconnectMqttClient() {
        stopThread = true;

        if (mqttClient == null) {
            return;
        }

        try {
            mqttClient.disconnect();
            mqttClient = null;
        } catch (MqttPersistenceException e) {
            e.printStackTrace();
        }
    }

    /**
     * 初始化群组列表
     * @throws Exception exception
     */
    public void initGroups() throws Exception {
        if (isGroupsLoaded) {
            return;
        }

        // 初始化用户群组
        Response response = RequestUtils.findCommunityGroup(NetConfig.currentUser.getUserId());
        if (response.isSuccessful()) {
            JSONObject jsonObject = new JSONObject(response.body().string());
            String resultCode = jsonObject.getString(RequestCallback
                    .RESULT_CODE);
            if (!Constants.REQUEST_OK.equals(resultCode)) {
                throw new Exception();
            }

            String list = jsonObject.getString(RequestCallback.LIST);
            Gson gson = new Gson();
            List<GroupNetBean> groups = gson.fromJson(list,
                    new TypeToken<List<GroupNetBean>>() {
                    }.getType());

            // 清除本地群组
            RuntimeExceptionDao dao = DatabaseHelper.getHelper(this)
                    .getRuntimeExceptionDao(GroupNetBean.class);
            DeleteBuilder db = dao.deleteBuilder();
            db.where().eq("ownerId", NetConfig.currentUser.getUserId());
            dao.delete(db.prepare());

            for (GroupNetBean group : groups) {
                group.setOwnerId(NetConfig.currentUser.getUserId());
                dao.create(group);

                for (RegisterUserNetBean user : group.getUsers()) {
                    // 清除该群组用户
                    RuntimeExceptionDao userDao = DatabaseHelper.getHelper(this)
                            .getRuntimeExceptionDao(RegisterUserNetBean.class);
                    DeleteBuilder userDb = userDao.deleteBuilder();
                    userDb.where().eq("ownerId", group.getGroupId());
                    userDao.delete(userDb.prepare());

                    // 存储入库
                    user.setOwnerId(group.getGroupId());
                    userDao.create(user);
                }
            }

            isGroupsLoaded = true;
        } else {
            throw new Exception();
        }
    }

    /**
     * 初始化联系人列表
     * @throws Exception 异常
     */
    private void initContacts() throws Exception {
        if (isContactsLoaded) {
            return;
        }

        Response response = RequestUtils.findContacts(NetConfig.currentUser.getUserId());
        if (response.isSuccessful()) {
            JSONObject jsonObject = new JSONObject(response.body().string());
            String resultCode = jsonObject.getString(RequestCallback.RESULT_CODE);
            if (!Constants.REQUEST_OK.equals(resultCode)) {
                throw new Exception();
            }

            String list = jsonObject.getString(RequestCallback.LIST);
            Gson gson = new Gson();
            List<RegisterUserNetBean> contacts = gson.fromJson(list,
                    new TypeToken<List<RegisterUserNetBean>>() {
                    }.getType());

            // 清除本地联系人
            RuntimeExceptionDao dao = DatabaseHelper.getHelper(this)
                    .getRuntimeExceptionDao(RegisterUserNetBean.class);
            DeleteBuilder db = dao.deleteBuilder();
            db.where().eq("ownerId", NetConfig.currentUser.getUserId());
            dao.delete(db.prepare());

            // 逐条存入联系人到数据库
            for (RegisterUserNetBean user : contacts) {
                RegisterUserNetBean u = findUserByUserId(user.getUserId());
                if (u != null) {
                    continue;
                }

                user.setOwnerId(NetConfig.currentUser.getUserId());
                dao.create(user);
            }

            Intent intent = new Intent(BroadCastActions.ACTION_RELOAD_CONTACTS);
            sendBroadcast(intent);
            isContactsLoaded = true;
        } else {
            throw new Exception();
        }
    }

    /**
     * 查询用户
     * @param userId 用户ID
     * @return 注册用户信息bean
     */
    private RegisterUserNetBean findUserByUserId(String userId) {
        RuntimeExceptionDao dao = DatabaseHelper.getHelper(this)
                .getRuntimeExceptionDao(RegisterUserNetBean.class);

        Map<String, String> params = new HashMap<String, String>();
        params.put("userId", userId);
        params.put("ownerId", NetConfig.currentUser.getUserId());

        List<RegisterUserNetBean> users = dao.queryForFieldValues(params);
        if (users != null && !users.isEmpty()) {
            return users.get(0);
        }

        return null;
    }

    /**
     * 服务与调用者信使
     */
    public class MqttBinder extends Binder {

        /**
         * 返回当前服务
         * @return 获取当前服务对象
         */
        public MqttService getService() {
            return MqttService.this;
        }
    }

    /**
     * 心跳
     */
    private class MyThread extends Thread {
        @Override
        public void run() {
            while (!stopThread) {

                if (RequestUtils.isNetworkConnected(MqttService.this)) {
                    try {
                        if (!isLoadingData) {
                            isLoadingData = true;

                            initContacts();
                            initGroups();
                            initKsdcMqttClient();
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                    isLoadingData = false;
                }

                try {
                    // 每个5秒向服务器发送一次请求
                    Thread.sleep(HEART_LINE);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
